<template>
  <div class="container">
    <!-- 视频预览 -->
    <video :src="videoPreview" controls class="video" v-if="videoPreview"></video>

    <!-- 源选择区域 -->
    <div class="source-selection">
      <label class="radio-label">
        <input
          type="radio"
          v-model="sourceType"
          value="url"
          name="sourceType"
        >
        网络视频地址
      </label>
      <label class="radio-label">
        <input
          type="radio"
          v-model="sourceType"
          value="file"
          name="sourceType"
        >
        本地视频文件
      </label>
    </div>

    <!-- 网络地址输入框 -->
    <div v-if="sourceType === 'url'" class="url-input">
      <input
        type="text"
        v-model="videoURL"
        placeholder="请输入视频URL"
        class="url-input-field"
      >
      <button @click="validateURL" :disabled="!videoURL">验证URL</button>
    </div>

    <!-- 本地文件选择 -->
    <div v-if="sourceType === 'file'" class="file-input">
      <input
        type="file"
        accept="video/*"
        @change="handleFileSelect"
        class="file-input-field"
      >
      <span v-if="selectedFileName">{{ selectedFileName }}</span>
    </div>

    <!-- 控制按钮 -->
    <div class="controls">
      <button
        @click="startTranscode"
        :disabled="isProcessing || !canTranscode"
      >
        {{ isProcessing ? 'Processing...' : 'Start Transcode' }}
      </button>
      <button @click="downloadVideo" :disabled="!video">下载视频</button>
      <button @click="cancelTranscode" :disabled="!isProcessing">取消</button>
    </div>

    <!-- 进度显示 -->
    <div class="progress">
      <div class="progress-bar" :style="{ width: progress + '%' }"></div>
      <span>{{ progress }}%</span>
    </div>

    <!-- 状态信息和日志 -->
    <p class="status-message">{{ message }}</p>
    <pre class="logs" v-if="ffmpegLogs">{{ ffmpegLogs }}</pre>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref, onUnmounted, computed } from 'vue'
import Worker from './ffmpeg.worker?worker'

export default defineComponent({
  name: 'VideoTranscoder',
  setup() {
    // 基础状态
    const sourceType = ref<'url' | 'file'>('url') // 源类型：网络地址/本地文件
    const videoURL = ref('') // 网络视频地址
    const localFile = ref<File | null>(null) // 本地视频文件
    const selectedFileName = ref('') // 选中的本地文件名
    const videoPreview = ref('') // 预览视频地址
    const video = ref('') // 转码后视频地址
    const message = ref('请选择视频源并开始转码')
    const ffmpegLogs = ref('')
    const isProcessing = ref(false)
    const progress = ref(0)
    const worker = ref<Worker | null>(null)
    let downloadBlob: Blob | null = null

    // 计算属性：是否可以开始转码
    const canTranscode = computed(() => {
      if (sourceType.value === 'url') {
        return !!videoURL.value && videoPreview.value
      } else {
        return !!localFile.value
      }
    })

    // 验证网络URL并预览
    const validateURL = async () => {
      if (!videoURL.value) return

      message.value = '验证URL有效性...'
      try {
        // 简单验证URL格式
        new URL(videoURL.value)

        // 尝试获取视频信息验证可用性
        const response = await fetch(videoURL.value, { method: 'HEAD' })
        if (!response.ok) throw new Error(`HTTP状态码: ${response.status}`)

        // 显示预览
        videoPreview.value = videoURL.value
        message.value = 'URL验证通过，可以开始转码'
      } catch (error) {
        message.value = `URL无效: ${(error as Error).message}`
        videoPreview.value = ''
      }
    }

    // 处理本地文件选择
    const handleFileSelect = (e: Event) => {
      const target = e.target as HTMLInputElement
      if (target.files && target.files[0]) {
        const file = target.files[0]
        localFile.value = file
        selectedFileName.value = file.name

        // 生成预览URL
        videoPreview.value = URL.createObjectURL(file)
        message.value = `已选择本地文件: ${file.name}`
      }
    }

    // 开始转码
    const startTranscode = async () => {
      if (isProcessing.value || !canTranscode.value) return

      isProcessing.value = true
      message.value = '初始化转码器...'
      ffmpegLogs.value = ''
      progress.value = 0
      video.value = ''

      // 创建Web Worker
      worker.value = new Worker()

      // 监听Worker消息
      worker.value.onmessage = (e) => {
        const { type, data } = e.data

        switch (type) {
          case 'log':
            ffmpegLogs.value += data + '\n'
            break
          case 'progress':
            progress.value = data.progress
            message.value = data.message
            break
          case 'complete':
            downloadBlob = new Blob([data.buffer], { type: 'video/mp4' })
            video.value = URL.createObjectURL(downloadBlob)
            message.value = '转码完成！可点击下载'
            isProcessing.value = false
            break
          case 'error':
            message.value = `错误: ${data}`
            isProcessing.value = false
            break
        }
      }

      // 向Worker发送源数据
      if (sourceType.value === 'url' && videoURL.value) {
        worker.value.postMessage({
          type: 'start',
          sourceType: 'url',
          data: videoURL.value
        })
      } else if (sourceType.value === 'file' && localFile.value) {
        // 读取本地文件为ArrayBuffer
        const fileReader = new FileReader()
        fileReader.onload = (e) => {
          worker.value?.postMessage({
            type: 'start',
            sourceType: 'file',
            data: e.target?.result // 传递文件的ArrayBuffer
          }, [e.target?.result as ArrayBuffer]) // 转移所有权，释放内存
        }
        fileReader.readAsArrayBuffer(localFile.value)
      }
    }

    // 下载视频
    const downloadVideo = () => {
      if (!downloadBlob) return

      const link = document.createElement('a')
      link.href = video.value
      link.download = 'converted-video.mp4'
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
    }

    // 取消转码
    const cancelTranscode = () => {
      if (worker.value) {
        worker.value.terminate()
        worker.value = null
      }
      message.value = '转码已取消'
      isProcessing.value = false
    }

    // 组件卸载时清理资源
    onUnmounted(() => {
      if (worker.value) {
        worker.value.terminate()
      }
      if (videoPreview.value) {
        URL.revokeObjectURL(videoPreview.value)
      }
      if (video.value) {
        URL.revokeObjectURL(video.value)
      }
    })

    return {
      sourceType,
      videoURL,
      selectedFileName,
      videoPreview,
      video,
      message,
      ffmpegLogs,
      isProcessing,
      progress,
      canTranscode,
      validateURL,
      handleFileSelect,
      startTranscode,
      downloadVideo,
      cancelTranscode
    }
  }
})
</script>

<style scoped>
.container {
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
  font-family: Arial, sans-serif;
}

.video {
  max-width: 100%;
  border: 1px solid #ddd;
  border-radius: 4px;
  margin: 20px 0;
}

.source-selection {
  margin: 15px 0;
  padding: 10px;
  background-color: #f5f5f5;
  border-radius: 4px;
}

.radio-label {
  margin-right: 20px;
  cursor: pointer;
}

.url-input {
  margin: 15px 0;
  display: flex;
  gap: 10px;
  align-items: center;
}

.url-input-field {
  flex: 1;
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
}

.file-input {
  margin: 15px 0;
}

.file-input-field {
  margin: 5px 0;
}

.controls {
  margin: 20px 0;
  display: flex;
  gap: 10px;
}

button {
  padding: 8px 16px;
  background-color: #4CAF50;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

button:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}

.progress {
  height: 20px;
  background-color: #f3f3f3;
  border-radius: 4px;
  margin: 10px 0;
  overflow: hidden;
  position: relative;
}

.progress-bar {
  height: 100%;
  background-color: #4CAF50;
  transition: width 0.3s ease;
}

.progress span {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  font-size: 14px;
}

.status-message {
  color: #333;
  margin: 10px 0;
}

.logs {
  background-color: #f8f8f8;
  border: 1px solid #ddd;
  border-radius: 4px;
  padding: 10px;
  margin-top: 15px;
  max-height: 200px;
  overflow: auto;
  font-size: 14px;
  white-space: pre-wrap;
}
</style>